<template>
  <main class="noselect colFlex">
    <section class="colFlex">
      <h1>计数器web版</h1>
      <h2>推荐用PC端控制台观察数据</h2>
    </section>

    <el-radio-group v-model="radios" :disabled="rDisabled">
      <el-radio :label="1"> timer-可精确至千分位，容易受阻塞影响 </el-radio>
      <el-radio :label="2">
        requestAFrame-可精确至百分位，抗阻塞效果更佳
      </el-radio>
    </el-radio-group>

    <section class="rowFlex">
      <el-button type="primary" @click="btClick()">{{
        btText.texts[btText.ind]
      }}</el-button>
      <el-button type="primary" @click="blocking()">{{
        block.texts[block.ind]
      }}</el-button>
    </section>

    <h3>计数器开启状态下点击变化中的数字可停止计数</h3>
  </main>
</template>

<script>
import { Plus } from "@element-plus/icons-vue";
import { ref } from "vue";

export default {
  name: "counter",
  components: { Plus },
  data() {
    return {
      radios: ref(2),
      blockTimerArr: [],
      block: {
        texts: ["开启阻塞", "关闭阻塞"],
        ind: 0,
      },
      rDisabled: false,
      btText: {
        texts: ["开始计时", "-"],
        ind: 0,
      },
      requestAF: () => {
        window.requestAnimationFrame =
          window.requestAnimationFrame ||
          function (fn) {
            return setTimeout(fn, 1000 / 60);
          };
        window.cancelAnimationFrame =
          window.cancelAnimationFrame || clearTimeout;
      },
    };
  },
  mounted() {
    this.showTimeM();
  },
  methods: {
    blocking() {
      let block = this.block;
      if (block.ind == 0) {
        block.ind = 1;
        console.log("阻塞已开启");
      } else {
        block.ind = 0;
        console.log("阻塞已关闭");
      }

      this.blockClock();
    },
    blockClock() {
      //阻塞
      if (this.block.ind == 1) {
        if (this.blockTimerArr.length == 0) {
          let timer = setInterval(() => {
            console.log("阻塞");
            let i = 0;
            while (i < 100000000) {
              i++;
            }
          }, 0);
          this.blockTimerArr.push(timer);
        }
      } else {
        console.log("阻塞", this.blockTimerArr.length);
        //清空定时器
        this.blockTimerArr.forEach((item) => {
          clearInterval(item);
        });
        this.blockTimerArr.splice(0, this.blockTimerArr.length);
      }
    },
    btClick() {
      let btText = this.btText;
      if (btText.ind == 0) {
        //初始状态
        btText.ind = 1;
        this.rDisabled = true;

        if (this.radios == 1) {
          this.countNum("timer");
        } else {
          this.countNum("AFrame");
        }

        console.log("开始计数");
      } else {
        this.rDisabled = false;
        btText.ind = 0;

        console.log("停止计数");
      }
    },
    countNum(mod) {
      //阀门
      if (this.btText.ind == 0) {
        return false;
      }

      //文字居中
      this.showTimeM();

      //参数
      //数据记录
      let startTime = new Date(); //起始时间
      let tmpTime = startTime; //暂存时间（数据记录）
      let lastshowTime = 0; //上次累计时间（数据记录）
      let timerArr = []; //timer数组

      //渲染
      let canShowT = false; //渲染起始阀门
      let showStep = 0.001; //渲染间隔（秒），大于等于inCycle
      if (mod != "timer") {
        showStep = 0.01;
      }
      let numLength = showStep.toString().replace(".", "").length - 1; //渲染精度

      //设置
      let step = 0.1; //精确位数（秒）
      let turbulence = 0.01; //偏移幅度，精细计时（百分比）
      if (mod != "timer") {
        step = 0.1;
        turbulence = 0.5;
      }
      let inCycle = (step * turbulence).toFixed(2); //数据记录最小间隔，大于等于0.001秒

      let reWTime = () => {
        let nowTime = new Date();
        let showTime = (nowTime - startTime) / 1000; //从开始的累计时间
        let timePass = (nowTime - tmpTime) / 1000; //本次记录到上次记录经历了多久
        let offset = timePass - inCycle; //数据记录中的偏移量

        if (timePass + offset >= inCycle) {
          //数据记录
          if (canShowT == false) {
            //稳定之前不输出数据
            if (timePass - offset == inCycle) {
              canShowT = true;
            }
          } else {
            //首次稳定以后开始输出数据
            if (showTime - lastshowTime >= showStep) {
              let putText = showTime.toFixed(numLength);
              let IntervalError = timePass - inCycle; //数据记录误差，不是渲染误差
              let drawError = showTime - lastshowTime - showStep;

              //控制台数据输出
              console.log(
                mod,
                "输出:" + putText,
                "数据误差:" + IntervalError,
                "渲染误差：" + drawError
              );

              //视图输出
              let lastshowT = this.btText.texts[1]; //记录上次时间
              this.btText.texts[1] = putText; //显示数据

              //文字居中
              if (putText.toString().length != lastshowT.toString().length) {
                this.showTimeM();
              }
              lastshowTime = showTime; //记录上次满足输出条件时的累计时间
            }
          }
          tmpTime = nowTime; //更新上次循环记录的时间
        }
      };

      //调用计时器
      if (mod == "timer") {
        if (timerArr.length == 0) {
          let timer = setInterval(() => {
            if (this.btText.ind == 1) {
              reWTime();
            } else {
              //清空定时器
              timerArr.forEach((item) => {
                clearInterval(item);
              });
              timerArr.splice(0, timerArr.length);

              this.showTimeM();
              this.btText.texts[1] = "-";
            }
          }, 0);

          timerArr.push(timer);
        }
      } else {
        let requestAFrame = () => {
          if (this.btText.ind == 1) {
            reWTime();
            requestAnimationFrame(requestAFrame);
          } else {
            this.showTimeM();
            this.btText.texts[1] = "-";
          }
        };
        requestAnimationFrame(requestAFrame);
      }
    },
    showTimeM() {
      requestAnimationFrame(() => {
        let elBt = document.querySelector(".el-button");
        let elBtSpan = document.querySelector(".el-button>span");
        elBtSpan.style.left =
          (elBt.offsetWidth - elBtSpan.offsetWidth) * 0.5 + "px";
      });
    },
  },
};
</script>

<style lang="scss" scoped >
main {
  & ::v-deep .el-radio-group {
    max-width: 80vw;
    display: flex;
    justify-content: flex-start;
  }
  & ::v-deep .el-radio {
    margin-bottom: calc(#{$vh} * 0.01);
  }
  & ::v-deep .el-radio__label {
    font-size: 0.8rem;
    word-break: break-all;
    white-space: normal;
  }
}

section ::v-deep(.el-button):nth-of-type(1) {
  width: 120px;
  display: flex;
  padding: 0;
  flex-flow: row nowrap;
  justify-content: start;

  & > span {
    position: relative;
    text-align: left;
  }
}

//全局样式-响应式
@media all and (orientation: landscape) {//横屏
    main {
        height:24rem;
    }
}
  
@media all and (orientation: portrait) {
    main {
        height:35rem;
    }
}

@media screen and (max-width: 50rem) {
  //小于一定宽度
  main ::v-deep .el-radio-group {
    width: 19.5rem;
  }
}
</style>
